﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using TerrainProcessor;

namespace ScorchedTanks
{
    enum PlayerStatus { Playing, Waiting}
    class SceneBattle : Scene
    {
        Camera mCurrentCamera;
        //-Lista de camaras
        List<Camera> Cameras = new List<Camera>();
        List<Camera> camerasToAdd = new List<Camera>();
        List<Camera> camerasToRemove = new List<Camera>();
        //-Lista de actores
        List<Actor3d> Actors = new List<Actor3d>();
        List<Actor3d> actorsToAdd = new List<Actor3d>();
        List<Actor3d> actorsToRemove = new List<Actor3d>();
        //------------------
        // Actores
        //Actor3d mMainActor;
        Tank mMainTank;
        Actor3d mSecondActor;
        Projectile mProjectile;
        Projectile mProjectile2;
        Explosion mExplosion;
        //Explosion mExplosion2;

        Model terreno;
        HeightMapInfo heightMapInfo;

        InputManager Input = new InputManager();

        SpriteBatch spriteBatch;
        SpriteFont myFont; 
        Networking globalNetworkObjet;
        ContentManager Content;
        GraphicsDeviceManager graphics;
            
        private Texture2D RadarImage;
        private Vector2 RadarImageCenter;
        static Texture2D pixel;

        //sounds 
        SoundEffectInstance soundEngineInstance;
        SoundEffectInstance soundMusicInstance;
        SoundEffect soundEngine;
        SoundEffect soundShoot;
        SoundEffect soundExplosion;
        SoundEffect mMusic;

        PlayerStatus mPlayerStatus;
        PlayerStatus mRemotePlayerStatus;
        bool mMissileshot = false;
        int fuel = 1000;
        int hp = 100;
        int enemyhp = 100;
        float angle = 45;
        float power = 40;
        static Vector2 RadarCenterPos = new Vector2(900, 120);
        private const float RadarRange = 200.0f;
        private const float RadarRangeSquared = RadarRange * RadarRange;
        private const float RadarScreenRadius = 120.0f;

        public SceneBattle(GraphicsDeviceManager g, ContentManager content, SpriteBatch sb, SpriteFont sf, Networking n)
        {
            Content = content;
            myFont = sf;
            spriteBatch = sb;
            globalNetworkObjet = n;
            graphics = g;

            // terreno
            terreno = Content.Load<Model>("mapa1");
            heightMapInfo = terreno.Tag as HeightMapInfo;

            // actores
            mMainTank = new Tank(Content, heightMapInfo, "SpiderSpyDrone");
            mSecondActor = new Actor3d(Content, "SpiderSpyDrone");
            mProjectile = new Projectile(Content, "projectile");
            mExplosion = new Explosion(Content, "projectile");

            //sonidos
            mMusic = Content.Load<SoundEffect>("music");
            soundMusicInstance = mMusic.CreateInstance();
            soundMusicInstance.Volume = 0.40f;
            soundMusicInstance.IsLooped = true;
            soundMusicInstance.Play();

            soundShoot = Content.Load<SoundEffect>("shoot");
            soundExplosion = Content.Load<SoundEffect>("explosion");
            soundEngine = Content.Load<SoundEffect>("engine");
            soundEngineInstance = soundEngine.CreateInstance();

            // radar
            RadarImage = Content.Load<Texture2D>("radar");
            RadarImageCenter = new Vector2(RadarImage.Width * 0.5f, RadarImage.Height * 0.5f);
            pixel = new Texture2D(g.GraphicsDevice, 1, 1);
            Color[] col = new Color[1];
            col[0] = Color.Red;
            pixel.SetData<Color>(col);

            // ubicacion de los actores
            Vector3 Pos1 = new Vector3(60, 0, 60); 
            Vector3 Pos2 = new Vector3(-60, 0, -60);
            Vector3 Pos1N = Pos1;
            Vector3 Pos2N = Pos2;
            Pos1N.Normalize();
            Pos2N.Normalize();

            if (globalNetworkObjet.networkSession.IsHost)
            { 
                if (heightMapInfo.IsOnHeightmap(Pos1))
                {
                    Pos1.Y = heightMapInfo.GetHeight(Pos1) + 2;
                    mMainTank.SetPosition(Pos1);
                }
                mMainTank.SetDirection(Pos2N);
                mPlayerStatus = PlayerStatus.Playing;
                mRemotePlayerStatus = PlayerStatus.Waiting;
            }
            else
            {
                if (heightMapInfo.IsOnHeightmap(Pos2))
                {
                    Pos2.Y = heightMapInfo.GetHeight(Pos2) + 2;
                    mMainTank.SetPosition(Pos2);
                }
                mMainTank.SetDirection(Pos1N);
                mPlayerStatus = PlayerStatus.Waiting;
                mRemotePlayerStatus = PlayerStatus.Playing;

            }
  
            Camera c = new Camera();
            Cameras.Add(c);
            mCurrentCamera = c;
            c.setActor(mMainTank);

            actorsToAdd.Add(mMainTank);
            actorsToAdd.Add(mSecondActor);

         }

        public override void update(float dTime)
        {
            // network updates

            globalNetworkObjet.writer.Write(mMainTank.position);
            globalNetworkObjet.writer.Write(mMainTank.rotation);
            globalNetworkObjet.writer.Write(hp);
            if (globalNetworkObjet.networkSession.IsHost)
            {
                if (mRemotePlayerStatus == PlayerStatus.Playing)
                {
                    globalNetworkObjet.writer.Write(true);
                }
                else
                {
                    globalNetworkObjet.writer.Write(false);
                }
            }
            if (mMissileshot) {
                globalNetworkObjet.writer.Write(true);
                globalNetworkObjet.writer.Write(mProjectile.position);
                globalNetworkObjet.writer.Write(mProjectile.direction);
                globalNetworkObjet.writer.Write((Decimal)mProjectile.speed);
                mMissileshot = false;
 
            }else{
                globalNetworkObjet.writer.Write(false);
            }


            LocalNetworkGamer localGamer = globalNetworkObjet.networkSession.LocalGamers[0];
            localGamer.SendData(globalNetworkObjet.writer, SendDataOptions.ReliableInOrder);

            while (localGamer.IsDataAvailable)
            {
                NetworkGamer sender;
                localGamer.ReceiveData(globalNetworkObjet.reader, out sender);
                if (sender.IsLocal)
                    break;

                mSecondActor.position = globalNetworkObjet.reader.ReadVector3();
                mSecondActor.rotation = globalNetworkObjet.reader.ReadVector3();
                enemyhp = globalNetworkObjet.reader.ReadInt32();
                bool tempb;
                if (!globalNetworkObjet.networkSession.IsHost)
                {
                    tempb = globalNetworkObjet.reader.ReadBoolean();

                    if (tempb)
                    {
                        mPlayerStatus = PlayerStatus.Playing;
                    }
                    else
                    {
                        mPlayerStatus = PlayerStatus.Waiting;
                    }
                }
                
                tempb = globalNetworkObjet.reader.ReadBoolean();
                if (tempb) {
                    mProjectile.position = globalNetworkObjet.reader.ReadVector3();
                    mProjectile.direction = globalNetworkObjet.reader.ReadVector3();
                    mProjectile.speed = (float)globalNetworkObjet.reader.ReadDecimal();

                    mProjectile.position.Y += 2;
                    mProjectile.isInUse = true;
                    mProjectile.readyToexit = false;
                    actorsToAdd.Add(mProjectile);

                    
                } 
            }
            globalNetworkObjet.networkSession.Update();
            
            if (hp <= 0)
            {
                globalNetworkObjet.networkSession.LocalGamers[0].Tag = "Lose";
                if (globalNetworkObjet.currentGameState == GameState.Playing)
                {
                    globalNetworkObjet.currentGameState = GameState.Ended;
                }
            }
            if (enemyhp <=0)
            {
                globalNetworkObjet.networkSession.LocalGamers[0].Tag = "Win";
                if (globalNetworkObjet.currentGameState == GameState.Playing)
                {
                    globalNetworkObjet.currentGameState = GameState.Ended;
                }
            }
            if (globalNetworkObjet.currentGameState != GameState.Playing)
            {
                readyToExit = true;
                soundMusicInstance.Stop();
                SceneManager.scenesToAdd.Add(new SceneDebrief(graphics, Content, spriteBatch, myFont, globalNetworkObjet));
            }

            ////updates!!!
            foreach (Camera c in Cameras)
            {
                c.update(dTime);
                if (c.readyToexit)
                {
                    camerasToRemove.Add(c);
                }
            }
            foreach (Actor3d a in Actors)
            {
               a.update(dTime);
                if (a.readyToexit)
                {
                    actorsToRemove.Add(a);
                }
            }

            if (mProjectile.readyToexit)
            {
                actorsToRemove.Add(mProjectile);
            }

            foreach (Actor3d a in actorsToAdd)
            {
                Actors.Add(a);
            }

            foreach (Actor3d a in actorsToRemove)
            {
                Actors.Remove(a);

            }
            actorsToAdd.Clear();
            actorsToRemove.Clear();

            if (mProjectile.isInUse)
            {
                mProjectile.update(dTime);

                if (!heightMapInfo.IsOnHeightmap(mProjectile.position))
                {
                    mExplosion.Explode(mProjectile.position);
                    actorsToAdd.Add(mExplosion);
                    fuel = 100;
                    mProjectile.isInUse = false;
                    mProjectile.readyToexit = true;
                    soundExplosion.Play();
                    if (globalNetworkObjet.networkSession.IsHost)
                        SwitchPlayers();

                 }
                else
                {
                    if (mProjectile.position.Y <= heightMapInfo.GetHeight(mProjectile.position))
                    {
                        mExplosion.Explode(mProjectile.position);
                        actorsToAdd.Add(mExplosion);
                        fuel = 100;
                        mProjectile.isInUse = false;
                        mProjectile.readyToexit = true;
                        soundExplosion.Play();
                        if (globalNetworkObjet.networkSession.IsHost)
                            SwitchPlayers();

                    }
                }
            }
            //checkeo de colisiones con la explosion.
            BoundingSphere bs, bs2;
            if (mExplosion.isInUse)
            {
                foreach (ModelMesh mesh in mMainTank.mModel.Meshes)
                {
                    bs = mesh.BoundingSphere;
                    bs.Center = Vector3.Transform(bs.Center, Matrix.CreateTranslation(mMainTank.position));
                    foreach (ModelMesh meshin in mExplosion.mModel.Meshes)
                    {
                        bs2 = meshin.BoundingSphere;
                        bs2.Center = Vector3.Transform(bs2.Center, Matrix.CreateTranslation(mExplosion.position));
                        bs2.Transform(Matrix.CreateScale(mExplosion.size));
                        if (bs.Intersects(bs2))
                        {
                            hp -= 1;
                        }
                    }
                }

            }
            base.update(dTime);
        }

        public override void draw(GraphicsDeviceManager g)
        {
            // primero a dibujar el terreno
            Matrix view = Matrix.CreateLookAt(mCurrentCamera.GetPosition(), mCurrentCamera.GetLookAt(), Vector3.Up);
            Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 4 / 3, 1, 10000);
            foreach (ModelMesh mesh in terreno.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.View = view;
                    effect.Projection = projection;
                    effect.EnableDefaultLighting();
                    effect.PreferPerPixelLighting = true;

                    // Set the fog to match the black background color
                    effect.FogEnabled = true;
                    effect.FogColor = Vector3.Zero;
                    effect.FogStart = 1000;
                    effect.FogEnd = 3200;

                    effect.SpecularColor = new Vector3(0.6f, 0.4f, 0.2f);
                    effect.SpecularPower = 8;
                }
                mesh.Draw();
            }

            // luego los actores
            foreach (Actor3d a in Actors)
            {
                a.Draw(g,mCurrentCamera);
            }


            // por ultimo la gui
            spriteBatch.Begin();
            spriteBatch.DrawString(myFont, "Hp= " + hp + "\nfuel= " + fuel + "\nEnemy Hp=" + enemyhp, new Vector2(21, 21), Color.Black);
            spriteBatch.DrawString(myFont, "Hp= " + hp + "\nfuel= " + fuel + "\nEnemy Hp=" + enemyhp, new Vector2(20, 20), Color.White);
            
            if (mPlayerStatus == PlayerStatus.Playing)
            {
                spriteBatch.DrawString(myFont, "Angle= " + angle + "\nPower= " + power, new Vector2(21, 601), Color.Black);
                spriteBatch.DrawString(myFont, "Angle= " + angle + "\nPower= " + power, new Vector2(20, 600), Color.White);
            }

            Vector2 diffVect = new Vector2(mSecondActor.position.X - mMainTank.position.X, mSecondActor.position.Z - mMainTank.position.Z);
            float distance = diffVect.LengthSquared();
            if (distance < RadarRangeSquared)
            {
                diffVect *= RadarScreenRadius / RadarRange;

                // We rotate each point on the radar so that the player is always facing UP on the radar
                diffVect = Vector2.Transform(diffVect, Matrix.CreateRotationZ(mMainTank.rotation.X + 135));

                // Offset coords from radar's center
                diffVect += RadarCenterPos;

                // Draw enemy dot on radar
                spriteBatch.Draw(pixel, diffVect, null, Color.Red, 0.0f, new Vector2(0.0f, 0.0f), 4.0f, SpriteEffects.None, 0.0f);
 
            }
            spriteBatch.Draw(RadarImage, RadarCenterPos, null, new Color(100, 100, 100, 150), 0.0f, RadarImageCenter, 120 / (RadarImage.Height * 0.5f), SpriteEffects.None, 0.0f);
            spriteBatch.End();

            base.draw(g);
        }

        public override void handleInput(InputManager Input)
        {

            if (mPlayerStatus == PlayerStatus.Playing && globalNetworkObjet.currentGameState == GameState.Playing)
            {
                if (Input.isKeyPressed(Keys.A))
                {
                    mMainTank.Rotate(0, 0.01f, 0);
                }
                if (Input.isKeyPressed(Keys.O))
                {
                    hp -= 1;
                }
               if (Input.isKeyPressed(Keys.D))
                {
                    mMainTank.Rotate(0, -0.01f, 0);
                }
                if (Input.isKeyPressed(Keys.W))
                {
                    if (fuel > 0)
                    {
                        Vector3 newPosition = mMainTank.position + mMainTank.direction;
                        if (heightMapInfo.IsOnHeightmap(newPosition))
                        {
                            mMainTank.Walkto(newPosition, true);

                            fuel -= 1;
                        
                        }
                    }
                }
                if (Input.isKeyPressed(Keys.S))
                {
                    if (fuel > 0)
                    {
                        Vector3 newPosition = mMainTank.position - mMainTank.direction;
                        if (heightMapInfo.IsOnHeightmap(newPosition))
                        {
                            mMainTank.Walkto(newPosition, true);
                            fuel -= 1;

                        }
                    }
                }
                if (Input.isKeyPressed(Keys.Up))
                {
                    angle += 0.1f;
                }
                if (Input.isKeyPressed(Keys.Down))
                {
                    angle -= 0.1f;
                }
                if (Input.isKeyPressed(Keys.Left))
                {
                    power -= 0.1f;
                }
                if (Input.isKeyPressed(Keys.Right))
                {
                    power += 0.1f;
                }

                if (Input.isNewMouseClick() && !mProjectile.isInUse)
                {
                    mProjectile.position = mMainTank.position;
                    mProjectile.position.Y += 2;
                    mProjectile.direction = Vector3.Lerp(mMainTank.direction, Vector3.Up, angle / 100);
                    mProjectile.speed = power/1000;
                    mProjectile.isInUse = true;
                    mProjectile.readyToexit = false;
                    actorsToAdd.Add(mProjectile);
                    soundShoot.Play();
                    mMissileshot = true;
                 }

                if (Input.isKeyPressed(Keys.S) || Input.isKeyPressed(Keys.W))
                {

                    if (soundEngineInstance.State == SoundState.Stopped)
                    {
                        soundEngineInstance.Volume = 0.75f;
                        soundEngineInstance.IsLooped = true;
                        soundEngineInstance.Play();
                    }
                    else
                        soundEngineInstance.Resume();
                }
                else
                {
                    if (soundEngineInstance.State == SoundState.Playing)
                        soundEngineInstance.Pause();
                }
          }
            base.handleInput(Input);
        }

        protected void SwitchPlayers()
        {
            if (mPlayerStatus == PlayerStatus.Playing){
                mPlayerStatus = PlayerStatus.Waiting;
                mRemotePlayerStatus = PlayerStatus.Playing;
            }
            else
            {
                mPlayerStatus = PlayerStatus.Playing;
                mRemotePlayerStatus = PlayerStatus.Waiting;
            }
       }
    }
}

